/**
 * 
 */
package truerefactor.refactor;

import java.util.ArrayList;
import java.util.List;

import truerefactor.graph.AttributeNode;
import truerefactor.graph.ClassNode;
import truerefactor.graph.CodeGraph;
import truerefactor.graph.CodeNode;
import truerefactor.graph.Edge;
import truerefactor.graph.EdgeType;
import truerefactor.graph.MethodNode;

/**
 * An implementation of the Replace Delegation with Inheritance Refactoring
 * Technique
 * 
 * @author Isaac
 */
public class DelegationToInheritance extends Refactoring {

    /**
     * 
     */
    public DelegationToInheritance()
    {
        this.shortName = "DELINH";
        this.name = "Replace Delegation with Inheritance";
        this.description = "";
    }

    /*
     * (non-Javadoc)
     * @see
     * truerefactor.refactor.Refactoring#execute(truerefactor.graph.CodeNode
     * [])
     */
    @Override
    public void execute(CodeGraph graph)
    {
        ClassNode delegating = (ClassNode) operands.get(0);
        ClassNode delegate = (ClassNode) operands.get(1);
        
        // 1. Make the delegating object a subclass of the delegate
        delegate.addSubClass(delegating);
        delegating.addParentClass(delegate);
        delegating.addExtends(delegate.getIdentifier());
        graph.insert(new Edge(delegate, delegating, EdgeType.Generalization));
        
        // 2. Set the delegate field to be the object itself
        
        
        // 3. Remove the simple delegation methods
        List<CodeNode> toRemove = new ArrayList<CodeNode>();
        for (CodeNode method : delegating.getMethods()) {
            if (method instanceof MethodNode) {
                if (((MethodNode) method).getStatements().size() < 3) {
                    for (MethodNode mNode : ((MethodNode) method).getOtherMethods()) {
                        if (mNode.getParentClass().equals(delegate)) {
                            toRemove.add(mNode);
                        }
                    }
                }
            }
        }
        
        for (int i = 0; i < toRemove.size(); i++) {
            graph.remove(toRemove.get(i));
        }
        
        // 4. Replace all other delegations with calls to the object itself
        
        // 5. Remove the delegate field.
        toRemove.clear();
        for (CodeNode attr : delegating.getAttributeByType(delegate.getClassName())) {
            if (attr instanceof AttributeNode) {
                toRemove.add(attr);
            }
        }
        
        for (int i = 0; i < toRemove.size(); i++) {
            graph.remove(toRemove.get(i));
        }
    }
}
